package simulaco.business;

import gminet.infra.business.BusinessException;
import gminet.infra.business.BusinessObject;
import gminet.infra.db.Transaction;
import gminet.infra.db.TransactionException;
import gminet.infra.toolkit.DateToolkit;

import java.sql.Connection;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Random;

import simulaco.dao.SimuladoUsuarioDAO;
import simulaco.dto.Concurso;
import simulaco.dto.Questao;
import simulaco.dto.SimuladoModelo;
import simulaco.dto.SimuladoModeloMateria;
import simulaco.dto.SimuladoUsuario;
import simulaco.dto.SimuladoUsuarioQuestao;
import simulaco.dto.SimuladoUsuarioSituacao;
import simulaco.dto.Usuario;

public class SimuladoUsuarioBusiness extends BusinessObject {

    public static SimuladoUsuario findByPK(int codigoSimulado) throws TransactionException {

        SimuladoUsuario simuladoUsuario = null;
        Transaction transaction = createTransaction();
        try {
            Connection conn = transaction.getConnection();
            simuladoUsuario = SimuladoUsuarioDAO.findByPK(codigoSimulado, conn);
        } finally {
            transaction.release();
        }
        return simuladoUsuario;
    }

    public static SimuladoUsuario findByPK(int codigoSimulado, int codigoUsuario) throws TransactionException {

        SimuladoUsuario simuladoUsuario = null;
        Transaction transaction = createTransaction();
        try {
            Connection conn = transaction.getConnection();
            simuladoUsuario = SimuladoUsuarioDAO.findByPK(codigoSimulado, conn);
            if (simuladoUsuario != null) {
                List<SimuladoUsuarioQuestao> listaSimuladoQuestoes;
                listaSimuladoQuestoes = SimuladoUsuarioQuestaoBusiness.findBySimuladoUsuario(codigoUsuario, codigoSimulado, conn);
                simuladoUsuario.setListaSimuladoQuestao(listaSimuladoQuestoes);
            }
        } finally {
            transaction.release();
        }
        return simuladoUsuario;
    }

    public static List<SimuladoUsuario> findAll() throws TransactionException {

        List<SimuladoUsuario> simuladoUsuarios = null;
        Transaction transaction = createTransaction();
        try {
            Connection conn = transaction.getConnection();
            simuladoUsuarios = SimuladoUsuarioDAO.findAll(conn);
        } catch (TransactionException te) {
            transaction.rollback();
            throw te;
        } finally {
            transaction.release();
        }
        return simuladoUsuarios;
    }

    public static List<SimuladoUsuario> findByUsuario(int codigoUsuario) throws TransactionException {

        List<SimuladoUsuario> simuladoUsuarios = null;
        Transaction transaction = createTransaction();
        try {
            Connection conn = transaction.getConnection();
            simuladoUsuarios = findByUsuario(codigoUsuario, conn);
        } catch (TransactionException te) {
            transaction.rollback();
            throw te;
        } finally {
            transaction.release();
        }
        return simuladoUsuarios;
    }

    protected static List<SimuladoUsuario> findByUsuario(int codigoUsuario, Connection conn)
            throws TransactionException {

        List<SimuladoUsuario> simuladoUsuarios = null;
        simuladoUsuarios = SimuladoUsuarioDAO.findByUsuario(new Usuario(codigoUsuario), conn);
        return simuladoUsuarios;
    }

    public static SimuladoUsuario insert(SimuladoUsuario simuladoUsuario, SimuladoModelo simuladoModelo) throws BusinessException, TransactionException {

        SimuladoUsuario newSimuladoUsuario = null;
        Transaction transaction = createTransaction();
        try {
            Connection conn = transaction.getConnection();
            // SIMULADO
            Date dataAtual = DateToolkit.getDate();
            int codigoUsuario = simuladoUsuario.getUsuario().getCodigo();
            simuladoUsuario.setCodigo(SimuladoUsuarioDAO.getNextCodigo(codigoUsuario, conn));
            // PREENCHER DADOS BASICOS
            if (simuladoUsuario.getSituacao().getCodigo() == 0) {
                simuladoUsuario.setSituacao(SimuladoUsuarioSituacao.NAO_INICIADO);
            }
            simuladoUsuario.setDataCadastro(dataAtual);
            SimuladoUsuarioDAO.insert(simuladoUsuario, conn);
            // GERAR QUESTOES
            List<Questao> listaQuestoesSimulado = new ArrayList<Questao>();
            List<SimuladoModeloMateria> listaMaterias = simuladoModelo.getListaSimuladoMaterias();
            for (SimuladoModeloMateria simuladoModeloMateria : listaMaterias) {
                List<Questao> listaQuestoes = new ArrayList<Questao>();
                //
                int materiaId = simuladoModeloMateria.getMateria().getCodigo();
                // RECUPERA LISTA CONCURSOS COM FILTRO DESEJADO
                int orgaoId = simuladoModeloMateria.getSimuladoModelo().getOrgao().getCodigo();
                int instituicaoId = simuladoModeloMateria.getSimuladoModelo().getInstituicao().getCodigo();
                int nivelId = simuladoModeloMateria.getSimuladoModelo().getNivel().getCodigo();
                List<Concurso> listaConcurso = ConcursoBusiness.findByOrgaoInstituicaoNivel(orgaoId, instituicaoId, nivelId, conn);
                // ADICIONA QUESTOES A LISTA 
                for (Concurso concurso : listaConcurso) {
                    int concursoId = concurso.getCodigo();
                    listaQuestoes.addAll(QuestaoBusiness.findByConcursoMateria(concursoId, materiaId, conn));
                }
                // RECUPERA QUESTOES ALEATORIAS DA LISTA DE QUESTOES 
                int totalQuestoes = listaQuestoes.size(); 
                int quantidade = simuladoModeloMateria.getQuantidadeQuestoes();
                if (totalQuestoes > quantidade) {
                    List<Integer> indicesUsados = new ArrayList<Integer>();
                    Random random = new Random();
                    for (int aux = 0; aux < quantidade; aux++) {
                        int index = random.nextInt(totalQuestoes);
                        while (indicesUsados.contains(index)) {
                            index = random.nextInt(totalQuestoes);
                        }
                        listaQuestoesSimulado.add(listaQuestoes.get(index));
                        indicesUsados.add(index);
                    }
                } else {
                    listaQuestoesSimulado.addAll(listaQuestoes);
                }
                
            }
            // ADICIONA QUESTOES SELECIONADAS NO SIMULADO
            for (Questao questao : listaQuestoesSimulado) {
                SimuladoUsuarioQuestao simuladoQuestao = new SimuladoUsuarioQuestao();
                simuladoQuestao.setSimuladoUsuario(simuladoUsuario);
                simuladoQuestao.setQuestao(questao);
                simuladoUsuario.getListaSimuladoQuestao().add(simuladoQuestao);
                SimuladoUsuarioQuestaoBusiness.insert(simuladoQuestao, conn);
            }
            // COMMIT
            transaction.commit();
            //
            newSimuladoUsuario = simuladoUsuario;
        } catch (TransactionException te) {
            transaction.rollback();
            throw te;
        } finally {
            transaction.release();
        }
        return newSimuladoUsuario;
    }

    public static void update(SimuladoUsuario simulado) throws BusinessException, TransactionException {

        Transaction transaction = createTransaction();
        try {
            Connection conn = transaction.getConnection();
            SimuladoUsuarioDAO.update(simulado, conn);
            //SimuladoUsuarioQuestaoBusiness.updateFromSimulado(simulado, conn);
            // COMMIT
            transaction.commit();
        } catch (TransactionException te) {
            transaction.rollback();
            throw te;
        } finally {
            transaction.release();
        }
    }

    public static void updateStatus(SimuladoUsuario simulado) throws BusinessException, TransactionException {

        Transaction transaction = createTransaction();
        try {
            Connection conn = transaction.getConnection();
            SimuladoUsuario auxSimuladoUsuario = SimuladoUsuarioDAO.findByPK(simulado.getCodigo(), conn);
            auxSimuladoUsuario.setSituacao(simulado.getSituacao());
            SimuladoUsuarioDAO.update(auxSimuladoUsuario, conn);
            // COMMIT
            transaction.commit();
        } catch (TransactionException te) {
            transaction.rollback();
            throw te;
        } finally {
            transaction.release();
        }
    }

    public static void delete(SimuladoUsuario simuladoUsuario) throws BusinessException, TransactionException {

        Transaction transaction = createTransaction();
        try {
            Connection conn = transaction.getConnection();
            // EXCLUI QUESTOES SIMULADO
            SimuladoUsuarioQuestaoBusiness.deleteBySimulado(simuladoUsuario, conn);
            // EXCLUI O SIMULADO
            SimuladoUsuarioDAO.delete(simuladoUsuario, conn);
            //
            transaction.commit();
        } catch (TransactionException te) {
            transaction.rollback();
            throw te;
        } finally {
            transaction.release();
        }
    }

}
